#include "Character.hh"

// Constructor, initializes character attributes
Character::Character(const std::string& name, const std::string& description, unsigned health, unsigned attack, unsigned defense)
    : name(name), description(description), health(health), maxHealth(health), attackPower(attack), defense(defense) {}

// Destructor, releases dynamically allocated items in the inventory
Character::~Character() 
{
    for (auto item : inventory) 
    {
        delete item;
    }
    inventory.clear();
}

// Determines if the character is alive
bool Character::isAlive() const 
{
    return health > 0;
}

// Character takes damage, actual damage = (damage - defense) (minimum is 0)
bool Character::takeDamage(unsigned damage) 
{
    unsigned int actualDamage;
    if (damage > defense) 
    {
        actualDamage = damage - defense;
    } 
    else 
    {
        actualDamage = 0;
    }

    if (actualDamage >= health) {
        health = 0;
    }
    else {
        health -= actualDamage;
    }
    return !isAlive();
}

// Attacks the target, calls the target's takeDamage method
bool Character::attack(ICharacter& target) 
{
    std::cout << name << " attacks " << target.getName() << "!\n";
    bool targetDied = target.takeDamage(attackPower);
    
    unsigned damage = 0;
    if (attackPower > target.getDefense()) 
    {
        damage = attackPower - target.getDefense();
    }
    std::cout << target.getName() << " takes " << damage << " points of damage!\n";

    return targetDied;
}

std::string Character::getName() const 
{
    return name;
}

std::string Character::getDescription() const 
{
    return description;
}

unsigned Character::getHealth() const 
{
    return health;
}

unsigned Character::getAttack() const 
{
    return attackPower;
}

unsigned Character::getDefense() const 
{
    return defense;
}

std::string Character::toString() const 
{
    return name + " (Health: " + std::to_string(health) + "/" + std::to_string(maxHealth) +
        ", Attack: " + std::to_string(attackPower) + ", Defense: " + std::to_string(defense) + ")";
}

void Character::addToInventory(Item* item) 
{
    inventory.push_back(item);
    //improve character attributes when item is obtained
    attackPower += item->bonusAttack;
    defense += item->bonusDefense;
    maxHealth += item->bonusHealth;
    health += item->bonusHealth; // Here we set current health also increases
    std::cout << "You obtained " << item->name << ", attributes improved!\n";
}

void Character::displayInventory() const 
{
    std::cout << "Inventory items:\n";
    if (inventory.empty()) {
        std::cout << "None\n";
    }
    else 
    {
        for (size_t i = 0; i < inventory.size(); ++i) 
        {
            std::cout << i + 1 << ". " << inventory[i]->toString() << "\n";
        }
    }
}

void Character::display() const 
{
    std::cout << toString() << "\n";
}

// Operator overload, facilitates adding items using the "+=" operator
Character& Character::operator+=(Item* item) 
{
    addToInventory(item);
    return *this;
}

// Operator overload: uses "-" to attack the target 
bool Character::operator-(ICharacter& target) 
{
    return attack(target);
}
